package com.yzr.extra_01;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static java.util.stream.Collectors.*;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class lambda_demo_01 {
    void t1(){

        //匿名类
        new Thread(new Runnable(){
            @Override
            public void run(){
                System.out.println("hello1");
            }
        }).start();
        //Lambda表达式
        new Thread(() -> System.out.println("hello2")).start();
    }

    void t2(){

        //使用Lambda表达式提供Supplier接口实现，返回OK字符串
        Supplier<String> stringSupplier = ()->"OK";
        //使用方法引用提供Supplier接口实现，返回空字符串
        Supplier<String> supplier1 = () -> new String();
        Supplier<String> supplier2 = String::new;
    }

    void t3(){

//Predicate接口是输入一个参数，返回布尔值。我们通过and方法组合两个Predicate条件，判断是否值大于0并且是偶数
        Predicate<Integer> positiveNumber = i -> i > 0;
        Predicate<Integer> evenNumber = i -> i % 2 == 0;
        assertTrue(positiveNumber.and(evenNumber).test(2));

//Consumer接口是消费一个数据。我们通过andThen方法组合调用两个Consumer，输出两行abcdefg
        Consumer<String> println = System.out::println;
        println.andThen(println).accept("abcdefg");

//Function接口是输入一个数据，计算后输出一个数据。我们先把字符串转换为大写，然后通过andThen组合另一个Function实现字符串拼接
        Function<String, String> upperCase = String::toUpperCase;
        Function<String, String> duplicate = s -> s.concat(s);
        assertThat(upperCase.andThen(duplicate).apply("test"), is("TESTTEST"));

//Supplier是提供一个数据的接口。这里我们实现获取一个随机数
        Supplier<Integer> random = ()-> ThreadLocalRandom.current().nextInt();
        System.out.println(random.get());

//BinaryOperator是输入两个同类型参数，输出一个同类型参数的接口。这里我们通过方法引用获得一个整数加法操作，通过Lambda表达式定义一个减法操作，然后依次调用
        BinaryOperator<Integer> add = Integer::sum;
        BinaryOperator<Integer> subtraction = (a, b) -> a - b;
        assertThat(subtraction.apply(add.apply(1, 2), 3), is(0));
    }
    @Test
    void t4(){
        ConcurrentHashMap<String,AtomicInteger> map = new ConcurrentHashMap();
        map.computeIfAbsent("1", k -> new AtomicInteger()).addAndGet(1);

        Arrays.asList("a", "b", "c").stream().mapToInt(String::hashCode).mapToObj(i->"");
        Random random = new Random();
        IntStream ints = random.ints(48, 122);
        List<Integer> collect = ints.boxed().collect(Collectors.toList());
        //生成一定位数的随机字符串
        List<Order> orders = new ArrayList<>();
        //生成一定位数的随机字符串
        System.out.println(random.ints(48, 122)
                .filter(i -> (i < 57 || i > 65) && (i < 90 || i > 97))
                .mapToObj(i -> (char) i)
                .limit(20)
                .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
                .toString());

        //所有下单的用户，使用toSet去重后实现字符串拼接
        System.out.println(orders.stream()
                .map(order -> order.getCustomerName()).collect(toSet())
                .stream().collect(joining(",", "[", "]")));

        //用toCollection收集器指定集合类型
        System.out.println(orders.stream().limit(2).collect(toCollection(LinkedList::new)).getClass());

        //使用toMap获取订单ID+下单用户名的Map
        orders.stream()
                .collect(toMap(Order::getId, Order::getCustomerName))
                .entrySet().forEach(System.out::println);

        //使用toMap获取下单用户名+最近一次下单时间的Map
        orders.stream()
                .collect(toMap(Order::getCustomerName, Order::getPlacedAt, (x, y) -> x.isAfter(y) ? x : y))
                .entrySet().forEach(System.out::println);

        //订单平均购买的商品数量
        System.out.println(orders.stream().collect(averagingInt(order ->
                order.getOrderItemList().stream()
                        .collect(summingInt(OrderItem::getProductQuantity)))));


    }


    //订单类
    @Data
    public class Order {
        private Long id;
        private Long customerId;//顾客ID
        private String customerName;//顾客姓名
        private List<OrderItem> orderItemList;//订单商品明细
        private Double totalPrice;//总价格
        private LocalDateTime placedAt;//下单时间
    }
    //订单商品类
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class OrderItem {
        private Long productId;//商品ID
        private String productName;//商品名称
        private Double productPrice;//商品价格
        private Integer productQuantity;//商品数量
    }
    //顾客类
    @Data
    @AllArgsConstructor
    public class Customer {
        private Long id;
        private String name;//顾客姓名
    }
}
